package com.example.multithread.controller;

import com.example.multithread.service.TestService;
import com.example.multithread.utils.ThreadVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Created by wangyg6 on 2020/8/10 17:17.
 * InheritableThreadLocal值传递，需要为当前线程新创建的子线程，
 * 对于线程池都是不适用，因为一般都是预先创建好的。
 * 不可能每次调用先创建线程池，所以值还是手动传递吧
 *
 */
@RestController
public class Test {
	private static final Logger log = LoggerFactory.getLogger(Test.class);
	@Autowired
	TestService testService;

	/**
	 * 测试InheritableThreadLocal
	 * @return
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	@GetMapping("/test")
	public List<String> test() throws ExecutionException, InterruptedException {
		List<String> result = new CopyOnWriteArrayList<>();
		List<Future<String>> futures = new ArrayList<Future<String>>();
		ThreadVariable.aaa.set("123");
		ThreadVariable.bbb.set("456");
		Callable<String> callable1 = () -> {
			//			log.error(Thread.currentThread().getName() + ":输出了->" +  new Random().nextInt(1000));
			System.out.println("AAA:" + ThreadVariable.aaa.get());
			System.out.println("BBB:" + ThreadVariable.bbb.get());

			Future<String> submit = Executors.newFixedThreadPool(2).submit(new Callable<String>() {
				@Override
				public String call() throws Exception {
					System.out.println("AAA-inner:" + ThreadVariable.aaa.get());
					System.out.println("BBB-inner:" + ThreadVariable.bbb.get());
					return Thread.currentThread().getName() + ":输出了->" + new Random().nextInt(1000);
				}
			});
			return submit.get();
		};

		ExecutorService executorService = Executors.newFixedThreadPool(2);
		StopWatch stopWatch = new StopWatch("test");
		stopWatch.start("a");
		for (int i = 0; i < 10; i++) {
			//			futures.add(testService.getThreadPool().submit(callable1));
			futures.add(testService.getThreadPool().submit(callable1));
		}

		futures.forEach(s -> {
			try {
				result.add(s.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		});
		stopWatch.stop();
		System.out.println(stopWatch.prettyPrint());
		return result;
	}

	/**
	 *测试{@link java.util.concurrent.CompletionService}
	 * 不使用的情况
	 "pool-9-thread-3:暂停了->25ms",
	 "pool-9-thread-1:暂停了->68ms",
	 "pool-9-thread-2:暂停了->50ms",
	 "pool-9-thread-4:暂停了->58ms",
	 "pool-9-thread-3:暂停了->86ms",
	 "pool-9-thread-2:暂停了->7ms",
	 "pool-9-thread-2:暂停了->40ms",
	 "pool-9-thread-4:暂停了->69ms",
	 "pool-9-thread-1:暂停了->69ms",
	 "pool-9-thread-2:暂停了->98ms",
	 "pool-9-thread-3:暂停了-> 1000ms",
	 "get总耗时:1111"
	 * @(#Executors)
	 * @return
	 */
	@GetMapping("/test2")
	public List<String> test2() {
		List<String> result = new CopyOnWriteArrayList<>();
		List<Future<String>> futures = new ArrayList<Future<String>>();
		StopWatch stopWatch = new StopWatch();
		Callable<String> callable1 = () -> {
			int i = new Random().nextInt(1000);
			Thread.sleep(i);
			return Thread.currentThread().getName() + ":暂停了->" + i + "ms";
		};
		Callable<String> callable2 = new Callable<String>() {
			@Override
			public String call() throws Exception {
				Thread.sleep(1000);
				return Thread.currentThread().getName() + ":暂停了-> 1000ms";

			}
		};
//		futures.add(testService.getThreadPool().submit(callable2));
		for (int i = 0; i < 30; i++) {
			//			futures.add(testService.getThreadPool().submit(callable1));
			futures.add(testService.getThreadPool().submit(callable1));
		}
		stopWatch.start("get耗时");
		futures.forEach(s -> {
			try {
				result.add(s.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		});
		stopWatch.stop();
		//		System.out.println(stopWatch.prettyPrint());
		result.add("get总耗时:" + stopWatch.getTotalTimeMillis());
		return result;
	}

	/**
	 * 测试{@link java.util.concurrent.CompletionService}
	 * 使用后
	 * @return
	 */
	@GetMapping("/test3")
	public List<String> test3() throws InterruptedException, ExecutionException {
		List<String> result = new CopyOnWriteArrayList<>();
		List<Future<String>> futures = new ArrayList<Future<String>>();
		ExecutorCompletionService<String> executors = new ExecutorCompletionService<String>(
				testService.getThreadPool());
		StopWatch stopWatch = new StopWatch();
		Callable<String> callable1 = () -> {
			int i = new Random().nextInt(1000);
			Thread.sleep(i);
			return Thread.currentThread().getName() + ":暂停了->" + i + "ms";
		};
		Callable<String> callable2 = new Callable<String>() {
			@Override
			public String call() throws Exception {
				Thread.sleep(1000);
				return Thread.currentThread().getName() + ":暂停了-> 1000ms";

			}
		};
//		futures.add(executors.submit(callable2));
		for (int i = 0; i < 30; i++) {
			//			futures.add(testService.getThreadPool().submit(callable1));
			futures.add(executors.submit(callable1));
		}
		stopWatch.start("get耗时");
	/*	futures.forEach(s -> {
			try {
				result.add(s.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		});*/
		for (int i = 0; i < futures.size(); i++) {
			result.add(executors.take().get());
		}
		stopWatch.stop();
		//		System.out.println(stopWatch.prettyPrint());
		result.add("get总耗时:" + stopWatch.getTotalTimeMillis());
		return result;
	}
}
